/*
 * Copyright (C) 2019 ByteDance Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bytedance.scene;

import com.bytedance.scene.interfaces.AbilityResultCallback;
import com.bytedance.scene.interfaces.PermissionResultCallback;
import com.bytedance.scene.navigation.ConfigurationChangedListener;
import com.bytedance.scene.utlity.ThreadUtility;
import com.bytedance.scene.utlity.Utility;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.ILifecycle;
import ohos.aafwk.ability.Lifecycle;
import ohos.aafwk.ability.fraction.Fraction;
import ohos.aafwk.ability.fraction.FractionAbility;
import ohos.aafwk.ability.fraction.FractionScheduler;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;

import java.util.Optional;

//TODO remove SceneAbilityCompatibilityLayerFragment when none Scene exists
public class AbilityCompatibilityUtility {
    private static SceneAbilityCompatibilityLayerFragment install(FractionAbility ability) {

        Optional<Fraction> optionalFraction=ability.getFractionManager().getFractionByTag(SceneAbilityCompatibilityLayerFragment.class.getName());
        SceneAbilityCompatibilityLayerFragment instance = null;

        if (optionalFraction.isPresent()) {
            instance= (SceneAbilityCompatibilityLayerFragment) optionalFraction.get();
        }

        if (instance == null) {
            instance = SceneAbilityCompatibilityLayerFragment.newIntent();
            FractionScheduler fractionScheduler = ability.getFractionManager().startFractionScheduler().add(ResourceTable.Id_content,instance,
                    SceneAbilityCompatibilityLayerFragment.class.getName());
            Utility.commitFragment(ability.getFractionManager(), fractionScheduler, false);
        }
        return instance;
    }
    public static void startAbilityForResult(final FractionAbility ability, final ILifecycle lifecycleOwner,
                                              final Intent intent, final int requestCode,
                                              final AbilityResultCallback resultCallback) {
        ThreadUtility.checkUIThread();
        if (isDestroyed(ability, lifecycleOwner)) {
            return;
        }
        final SceneAbilityCompatibilityLayerFragment fragment = install(ability);
        if (fragment.getFractionAbility()!=null) {
            fragment.startAbilityForResultByScene(lifecycleOwner, intent, requestCode, resultCallback);
        } else {
            fragment.addOnAbilityCreatedCallback(new SceneAbilityCompatibilityLayerFragment.OnAbilityCreatedCallback() {
                @Override
                public void onAbilityCreated() {
                    fragment.removeOnAbilityCreatedCallback(this);
                    if (isDestroyed(ability, lifecycleOwner)) {
                        return;
                    }
                    fragment.startAbilityForResultByScene(lifecycleOwner, intent, requestCode, resultCallback);
                }
            });
        }
    }

    public static void startAbilityForResult(final FractionAbility ability, final ILifecycle lifecycleOwner,
                                              final Intent intent, final int requestCode,
                                              final IntentParams options,
                                              final AbilityResultCallback resultCallback) {
        ThreadUtility.checkUIThread();
        if (isDestroyed(ability, lifecycleOwner)) {
            return;
        }
        final SceneAbilityCompatibilityLayerFragment fragment = install(ability);
        if (fragment.getFractionAbility()!=null) {
            fragment.startAbilityForResultByScene(lifecycleOwner, intent, requestCode, options, resultCallback);
        } else {
            fragment.addOnAbilityCreatedCallback(new SceneAbilityCompatibilityLayerFragment.OnAbilityCreatedCallback() {
                @Override
                public void onAbilityCreated() {
                    fragment.removeOnAbilityCreatedCallback(this);
                    if (isDestroyed(ability, lifecycleOwner)) {
                        return;
                    }
                    fragment.startAbilityForResultByScene(lifecycleOwner, intent, requestCode, options, resultCallback);
                }
            });
        }
    }

    public static void requestPermissions(final FractionAbility ability, final ILifecycle lifecycleOwner,
                                          final String[] permissions, final int requestCode,
                                          final PermissionResultCallback resultCallback) {
        ThreadUtility.checkUIThread();
        if (isDestroyed(ability, lifecycleOwner)) {
            return;
        }
        final SceneAbilityCompatibilityLayerFragment fragment = install(ability);
        if (fragment.getFractionAbility()!=null) {
            fragment.requestPermissionsByScene(lifecycleOwner, permissions, requestCode, resultCallback);
        } else {
            fragment.addOnAbilityCreatedCallback(new SceneAbilityCompatibilityLayerFragment.OnAbilityCreatedCallback() {
                @Override
                public void onAbilityCreated() {
                    fragment.removeOnAbilityCreatedCallback(this);
                    if (isDestroyed(ability, lifecycleOwner)) {
                        return;
                    }
                    fragment.requestPermissionsByScene(lifecycleOwner, permissions, requestCode, resultCallback);
                }
            });
        }
    }

    public static void addConfigurationChangedListener(final FractionAbility ability, final ILifecycle lifecycleOwner,
                                                       final ConfigurationChangedListener configurationChangedListener) {
        ThreadUtility.checkUIThread();
        if (isDestroyed(ability, lifecycleOwner)) {
            return;
        }
        final SceneAbilityCompatibilityLayerFragment fragment = install(ability);
        if (fragment.getFractionAbility()!=null) {
            fragment.addConfigurationChangedListener(lifecycleOwner, configurationChangedListener);
        } else {
            fragment.addOnAbilityCreatedCallback(new SceneAbilityCompatibilityLayerFragment.OnAbilityCreatedCallback() {
                @Override
                public void onAbilityCreated() {
                    fragment.removeOnAbilityCreatedCallback(this);
                    if (isDestroyed(ability, lifecycleOwner)) {
                        return;
                    }
                    fragment.addConfigurationChangedListener(lifecycleOwner, configurationChangedListener);
                }
            });
        }
    }

    private static boolean isDestroyed(Ability ability, final ILifecycle lifecycleOwner) {
        if (!Utility.isAbilityStatusValid(ability)) {
            return true;
        }

        return lifecycleOwner.getLifecycle().getLifecycleState() == Lifecycle.Event.ON_STOP;
    }
}
